package org.sqlproc.engine.model;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Version;

import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

/**
*
* Entity representing PhysicalMedia.
*/
@Entity
@Table(name = "PHYSICALMEDIA")
//@EntityListeners({org.hibernate.validator.event.JPAValidateListener.class,
//    org.fornax.cartridges.sculptor.framework.domain.AuditListener.class
//})
public class PhysicalMedia {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Long id;
    @Column(name = "STATUS", nullable = false, length = 3)
    @Length(max = 3)
    @NotEmpty
    private String status;
    @Column(name = "LOCATION", nullable = false, length = 100)
    @NotEmpty
    private String location;
    @Column(name = "UUID", nullable = false, length = 255, unique = true)
    private String uuid;
    @Column(name = "CREATEDDATE")
    @Type(type = "timestamp")
    private Date createdDate;
    @Column(name = "CREATEDBY", length = 50)
    private String createdBy;
    @Column(name = "LASTUPDATED")
    @Type(type = "timestamp")
    private Date lastUpdated;
    @Column(name = "LASTUPDATEDBY", length = 50)
    private String lastUpdatedBy;
    @Version
    @Column(name = "VERSION")
    private Long version;
    @ManyToOne()
    @JoinColumn(name = "LIBRARY")
    @ForeignKey(name = "FK_PHYSICALMEDIA_LIBRARY")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Library library;
    @ManyToMany(cascade =  {
        CascadeType.ALL}
    )
    @JoinTable(name = "MEDIA_PHYSICALMEDIA", joinColumns =  {
        @JoinColumn(name = "PHYSICALMEDIA")
    }
    , inverseJoinColumns =  {
        @JoinColumn(name = "MEDIA")
    }
    )
    @ForeignKey(name = "FK_MEDIA_PHYSICALMEDIA_PHYSICALMEDIA", inverseName = "FK_MEDIA_PHYSICALMEDIA_MEDIA")
    @NotEmpty
    private Set<Media> media = new HashSet<Media>();

    public PhysicalMedia() {
    }

    public Long getId() {
        return id;
    }

    /**
     * The id is not intended to be changed or assigned manually, but
     * for test purpose it is allowed to assign the id.
     */
    protected void setId(Long id) {
        if ((this.id != null) && !this.id.equals(id)) {
            throw new IllegalArgumentException(
                "Not allowed to change the id property.");
        }
        this.id = id;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }

    public Date getLastUpdated() {
        return lastUpdated;
    }

    public void setLastUpdated(Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    public String getLastUpdatedBy() {
        return lastUpdatedBy;
    }

    public void setLastUpdatedBy(String lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    /**
     * This domain object doesn't have a natural key
     * and this random generated identifier is the
     * unique identifier for this domain object.
     */
    public String getUuid() {

        // lazy init of UUID
        if (uuid == null) {
            uuid = java.util.UUID.randomUUID().toString();
        }
        return uuid;
    }

    @SuppressWarnings("unused")
    @PrePersist
    private void initUuid() {
        getUuid();
    }

    public Library getLibrary() {
        return library;
    }

    public void setLibrary(Library library) {
        this.library = library;
    }

    public Set<Media> getMedia() {
        return media;
    }

    /**
     * Adds an object to the bidirectional many-to-many
     * association in both ends.
     * It is added the collection {@link #getMedia}
     * at this side and to the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getPhysicalMedia}
     * at the opposite side.
     */
    public void addMedia(Media mediaElement) {
        this.media.add(mediaElement);
        mediaElement.getPhysicalMedia().add((PhysicalMedia) this);
    }

    /**
     * Removes an object from the bidirectional many-to-many
     * association in both ends.
     * It is removed from the collection {@link #getMedia}
     * at this side and from the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getPhysicalMedia}
     * at the opposite side.
     */
    public void removeMedia(Media mediaElement) {
        this.media.remove(mediaElement);
        mediaElement.getPhysicalMedia().remove((PhysicalMedia) this);
    }

    /**
     * Removes all object from the bidirectional
     * many-to-many association in both ends.
     * All elements are removed from the collection {@link #getMedia}
     * at this side and from the collection
     * {@link org.fornax.cartridges.sculptor.examples.library.media.domain.Media#getPhysicalMedia}
     * at the opposite side.
     */
    public void removeAllMedia() {
        for (Media d : this.media) {
            d.getPhysicalMedia().remove((PhysicalMedia) this);
        }
        this.media.clear();

    }

    /**
     * This method is used by equals and hashCode.
     * @return {{@link #getUuid}
     */
    public Object getKey() {
        return getUuid();
    }
}
